/*
 * Powered By dico
 * Since 2017 - 2018
 */
package com.seeyoui.kensite.bussiness.exam.exam.controller;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.fastjson.JSON;
import com.seeyoui.kensite.bussiness.exam.common.Const;
import com.seeyoui.kensite.bussiness.exam.common.Method;
import com.seeyoui.kensite.bussiness.exam.exam.domain.Exam;
import com.seeyoui.kensite.bussiness.exam.exam.service.ExamQueryService;
import com.seeyoui.kensite.bussiness.exam.exam.service.ExamService;
import com.seeyoui.kensite.bussiness.exam.examResult.domain.ExamResult;
import com.seeyoui.kensite.bussiness.exam.examResult.service.ExamResultService;
import com.seeyoui.kensite.bussiness.exam.exercise.domain.Exercise;
import com.seeyoui.kensite.bussiness.exam.exercise.service.ExerciseService;
import com.seeyoui.kensite.bussiness.exam.question.domain.Question;
import com.seeyoui.kensite.bussiness.exam.question.domain.QuestionVO;
import com.seeyoui.kensite.bussiness.exam.question.service.QuestionService;
import com.seeyoui.kensite.bussiness.exam.questionOption.domain.QuestionOption;
import com.seeyoui.kensite.bussiness.exam.questionOption.service.QuestionOptionService;
import com.seeyoui.kensite.common.base.controller.BaseController;
import com.seeyoui.kensite.common.base.domain.EasyUIDataGrid;
import com.seeyoui.kensite.common.base.domain.Page;
import com.seeyoui.kensite.common.constants.StringConstant;
import com.seeyoui.kensite.common.util.CacheUtils;
import com.seeyoui.kensite.common.util.DateUtils;
import com.seeyoui.kensite.common.util.RequestResponseUtil;
import com.seeyoui.kensite.common.util.Result;
import com.seeyoui.kensite.common.util.StringUtils;
import com.seeyoui.kensite.common.util.excel.ExportExcel;
import com.seeyoui.kensite.framework.system.util.UserUtils;
/**
 * Exam
 * @author dico
 * @version 2.0
 * @since 1.0
 * @date 2018-01-10
 */

@Controller
@RequestMapping(value = "exam/exam")
public class ExamController extends BaseController {
	
	@Autowired
	private ExamService examService;
	@Autowired
	private ExamQueryService examQueryService;
	@Autowired
	private ExamResultService examResultService;
	@Autowired
	private ExerciseService exerciseService;
	@Autowired
	private QuestionService questionService;
	@Autowired
	private QuestionOptionService questionOptionService;
	
	/**
	 * 展示列表页面
	 * @param modelMap
	 * @param module
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:view")
	@RequestMapping(value = "/{page}")
	public ModelAndView view(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, @PathVariable String page) throws Exception {
		return new ModelAndView("bussiness/exam/exam/"+page, modelMap);
	}
	
	/**
	 * 根据ID查询单条数据
	 * @param modelMap
	 * @param module
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:select")
	@RequestMapping(value = "/data/{id}")
	@ResponseBody
	public Object data(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, @PathVariable String id) throws Exception {
		Exam exam = examService.findOne(id);
		return exam;
	}
	
	/**
	 * 根据ID查询单条数据并返回相应表单
	 * @param modelMap
	 * @param module
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:view")
	@RequestMapping(value = "/form/{page}/{id}")
	public ModelAndView form(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, @PathVariable String page, @PathVariable String id) throws Exception {
		Exam exam = examService.findOne(id);
		modelMap.put("exam", exam);
		return new ModelAndView("bussiness/exam/exam/"+page, modelMap);
	}
	
	/**
	 * 获取列表展示数据
	 * @param modelMap
	 * @param exam
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:select")
	@RequestMapping(value = "/list/data", method=RequestMethod.POST)
	@ResponseBody
	public Object listData(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, Exam exam) throws Exception {
		List<Exam> examList = examService.findList(exam);
		int total = examService.findTotal(exam);
		EasyUIDataGrid eudg = new EasyUIDataGrid();
		eudg.setTotal(String.valueOf(total));
		eudg.setRows(examList);
		return eudg;
	}
	
	/**
	 * 获取列表展示数据带分页器用于jsp自己做分页
	 * @param modelMap
	 * @param exam
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:view")
	@RequestMapping(value = "/list/page", method=RequestMethod.POST)
	@ResponseBody
	public Object listPage(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, Exam exam) throws Exception {
		List<Exam> examList = examService.findList(exam);
		int total = examService.findTotal(exam);
		Page<Exam> page = new Page<Exam>(exam.getPage(), exam.getRows(), total);
		Map<String, Object> dataMap = new HashMap<String, Object>();
		dataMap.put("rows", examList);
		dataMap.put("page", page);
		return dataMap;
	}
	
	/**
	 * 获取所有数据
	 * @param modelMap
	 * @param exam
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:select")
	@RequestMapping(value = "/list/all", method=RequestMethod.POST)
	@ResponseBody
	public Object listAll(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, Exam exam) throws Exception {
		List<Exam> examList = examService.findAll(exam);
		return examList;
	}
	
	/**
	 * 保存新增的数据
	 * @param modelMap
	 * @param exam
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:insert")
	@RequestMapping(value = "/save", method=RequestMethod.POST)
	@ResponseBody
	public String save(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, Exam exam) throws Exception {
		if (!beanValidator(modelMap, exam)){
			RequestResponseUtil.putResponseStr(session, response, request, modelMap, StringConstant.FALSE);
			return null;
		}
		exam.setDuration(String.valueOf(DateUtils.getMinuteDistanceOfTwoDate(exam.getStartTime(), exam.getEndTime())));
		examService.save(exam);
		RequestResponseUtil.putResponseStr(session, response, request, modelMap, StringConstant.TRUE);
		return null;
	}
	
	/**
	 * 保存修改的数据
	 * @param modelMap
	 * @param exam
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:update")
	@RequestMapping(value = "/update", method=RequestMethod.POST)
	@ResponseBody
	public String update(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, Exam exam) throws Exception {
		if (!beanValidator(modelMap, exam)){
			RequestResponseUtil.putResponseStr(session, response, request, modelMap, StringConstant.FALSE);
			return null;
		}
		exam.setDuration(String.valueOf(DateUtils.getMinuteDistanceOfTwoDate(exam.getStartTime(), exam.getEndTime())));
		examService.update(exam);
		RequestResponseUtil.putResponseStr(session, response, request, modelMap, StringConstant.TRUE);
		return null;
	}
	
	/**
	 * 删除数据库
	 * @param modelMap
	 * @param examId
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:delete")
	@RequestMapping(value = "/delete", method=RequestMethod.POST)
	@ResponseBody
	public String delete(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, String id) throws Exception {
		List<String> listId = Arrays.asList(id.split(","));
		examService.delete(listId);
		RequestResponseUtil.putResponseStr(session, response, request, modelMap, StringConstant.TRUE);
		return null;
	}
	
	/**
	 * 假删除
	 * @param modelMap
	 * @param exam
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:delete")
	@RequestMapping(value = "/remove", method=RequestMethod.POST)
	@ResponseBody
	public String remove(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, Exam exam) throws Exception {
		examService.remove(exam);
		RequestResponseUtil.putResponseStr(session, response, request, modelMap, StringConstant.TRUE);
		return null;
	}

	/**
	 * 导出Excel数据
	 * @param modelMap
	 * @param exam
	 * @return
	 * @throws Exception
	 */
	//@RequiresPermissions("exam:exam:export")
	@RequestMapping(value = "/export")
	public String export(HttpSession session,
			HttpServletResponse response, HttpServletRequest request,
			ModelMap modelMap, Exam exam) throws Exception {
		String fileName = DateUtils.getDate("yyyyMMddHHmmss")+".xlsx";
		List<Exam> examList = examService.findAll(exam);
		new ExportExcel(null, Exam.class).setDataList(examList).write(response, fileName).dispose();
		return null;
	}
	
	/**
	 * 跳转到考试页面开始考试
	 * @return
	 */
	@RequestMapping("/goExamPage")
	public String goExamPage(HttpServletRequest request, ModelMap modelMap, String libraryId, Integer single, Integer multiple,
			Integer judge, Integer duration) {
		String userId = UserUtils.getUser(request).getId();
		if (StringUtils.isNotEmpty(userId) && StringUtils.isNotEmpty(libraryId)) {
			// 是练习
			Exercise exercise = exerciseService.create(userId, libraryId, single, multiple, judge, duration);
			modelMap.addAttribute("exerciseId", exercise.getId());
			List<QuestionVO> lsQuestions = exerciseService.start(exercise, single, multiple, judge);
			CacheUtils.put("QuestionsInExerciseId_" + exercise.getId(), Result.success(lsQuestions));
		}
		return "partybuild/examPage";
	}
	
	/**
	 * 查询登录用户在今天将要进行的考试列表，按考试开始时间倒序排序
	 * 注意：试卷总分保存在remarks字段
	 * @return Result
	 * @throws Exception
	 */
	@RequestMapping(value = "/listTodayExamByUser", method=RequestMethod.POST)
	@ResponseBody
	public Result listTodayExamByUser(HttpSession session,
			HttpServletResponse response, HttpServletRequest request) throws Exception {
		List<Exam> lsExams = examQueryService.findListForTodayByUser(UserUtils.getUser(request).getId());
		return Result.success(lsExams);
	}
	
	/**
	 * 获取指定考试的状态<br>
	 * 0:该考试不存在<br>
	 * 1:考试未开始<br>
	 * 2:考试进行中<br>
	 * 3:考试已结束<br>
	 * @param examId
	 * @return Result
	 * @throws Exception
	 */
	@RequestMapping(value = "/examState", method=RequestMethod.POST)
	@ResponseBody
	public Result examState(HttpSession session,
			HttpServletResponse response, HttpServletRequest request, String examId) throws Exception {
		Exam exam = examService.findOne(examId);
		if(null == exam) {
			return Result.success("0", "该考试不存在");
		}
		
		long now = System.currentTimeMillis();
		// 可以提前20秒进入考试
		if (now < (exam.getStartTime().getTime() - 20 * 1000)) {
			return Result.success("1", "考试开始时间是%s，请等待", DateUtils.formatDateTime(exam.getStartTime()));
		}
		if(now > exam.getEndTime().getTime()) {
			return Result.success("3", "该考试已经结束");
		}
		if(now > (exam.getEndTime().getTime() - 300 * 1000)){
			return Result.success("4", "已错过最后答题时间，不能参加考试");
		}
		return Result.success("2", "考试进行中");
	}
	
	/**
	 * 获取指定练习的全部试题，练习和复习均使用该接口获取试题
	 * @param exerciseId
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/listQuestionByExerciseId", method=RequestMethod.POST)
	@ResponseBody
	public Result listQuestionByExerciseId(HttpSession session,
			HttpServletResponse response, HttpServletRequest request, String exerciseId) throws Exception {
		Exercise exercise = exerciseService.findOne(exerciseId);
		if (null == exercise) {
			return Result.failure("该练习不存在");
		}
		
		if (StringUtils.isEmpty(exercise.getResult())) {
			// 未提交
			Object object = CacheUtils.get("QuestionsInExerciseId_" + exerciseId);
			if(null == object) {
				return Result.failure("该练习已经过期，请重新练习");
			}

			// 练习
			Result result = (Result) CacheUtils.get("QuestionsInExerciseId_" + exerciseId);
			CacheUtils.remove("QuestionsInExerciseId_" + exerciseId);
			return result;
		}
		
		// 已经提交答案，开始复习
		@SuppressWarnings("unchecked")
		Map<String, String> mapResults = (Map<String, String>) JSON.parse(exercise.getResult());
		List<QuestionVO> lsQuestions = new ArrayList<>();
		for (Entry<String, String> entry : mapResults.entrySet()) {
			Question question = questionService.findOne(entry.getKey());
			QuestionVO questionVO = QuestionVO.instance(question);
			questionVO.setUserAnswer(entry.getValue());
			
			/*if(Const.QUESTION_TYPE_ID_SINGLE.equals(question.getQuestionTypeId())) {
				questionVO.setQuestionTypeId("single"); // 单选题
			} else if (Const.QUESTION_TYPE_ID_MULTIPLE.equals(question.getQuestionTypeId())) {
				questionVO.setQuestionTypeId("multiple"); // 多选题
			} else if (Const.QUESTION_TYPE_ID_JUDGE.equals(question.getQuestionTypeId())) {
				questionVO.setQuestionTypeId("judge"); // 判断题
			}*/
			questionVO.setOptionList(questionOptionService.findByQuestionId(questionVO.getId()));
			
			lsQuestions.add(questionVO);
		}
		
		return Result.success(lsQuestions);
	}
	
	/**
	 * 获取指定考试的全部试题
	 * @param examId
	 * @return Result
	 * @throws Exception
	 */
	@RequestMapping(value = "/listQuestionByExamId", method=RequestMethod.POST)
	@ResponseBody
	public Result listQuestionByExamId(HttpSession session,
			HttpServletResponse response, HttpServletRequest request, String examId, String exerciseId) throws Exception {
		Exam exam = examService.findOne(examId);
		if(null == exam) {
			return Result.failure("该考试不存在");
		}
		
		long now = System.currentTimeMillis();
		// 可以提前20秒进入考试
		if (now < (exam.getStartTime().getTime() - 20 * 1000)) {
			return Result.failure("考试开始时间是%s，请等待", exam.getStartTime());
		}
		
		// 当前登录用户ID
		String userId = UserUtils.getUser(request).getId();
		// 初始化新增该登录用户的考试结果记录
		ExamResult examResult = examResultService.findByUserIdAndExamId(userId, examId);
		if(null == examResult) {
			// 最多给迟到考生5分钟(300*1000)的答题时间
			if (now > (exam.getEndTime().getTime() - 300 * 1000)) {
				// 当前考试已经结束，该登录用户华丽的错过了该考试
				return Result.failure("该考试已经结束，您错过了该考试");
			}
			//examResultService.save(userId, examId);
			Result result = findQuestionsForExam(request, examId);
			if (result.getState() == 1) {
				// 剩余考试分钟数
				result.setMsg(String.valueOf(DateUtils.getMinuteDistanceOfTwoDate(new Date(), exam.getEndTime())));
			}
			return result;
		} else {
			if(null == examResult.getSubmitTime()) {
				// 还未交卷
				if (now < exam.getEndTime().getTime()) {
					// 可以重新开始答题
					Result result = findQuestionsForExam(request, examId);
					if (result.getState() == 1) {
						// 剩余考试分钟数
						result.setMsg(String.valueOf(DateUtils.getMinuteDistanceOfTwoDate(new Date(), exam.getEndTime())));
					}
					return result;
				} else {
					// 已经放弃
					return Result.failure("您已经放弃了该考试");
				}
			} else {
				// 已经交卷
				if (now < exam.getEndTime().getTime()) {
					// 提前交卷
					return Result.failure("考试未结束，还不可以复习");
				} else {
					// 复习试卷
					return findQuestionsForReview(request, examId, examResult);
				}
			}
		}
	}
	
	/**
	 * 获取指定考试的全部试题，用于考试，缓存试题，不用于复习
	 * @param examId
	 * @return Result
	 */
	private Result findQuestionsForExam(HttpServletRequest request, String examId) {
		Result result = (Result) CacheUtils.get("QuestionsInExamId_" + examId);
		if (null != result) {
			// 从缓存中获取
			return result;
		}
		
		List<QuestionVO> lsQuestions = examQueryService.findListQuestionByExamId(examId);
		List<QuestionOption> lsOptions = examQueryService.findListQuestionOptionByExamId(examId);
		Map<String, QuestionVO> mapId2QuestionVO = Method.convertListToMap(lsQuestions);
		
		// 将试题选项与试题关联
		for (QuestionOption questionOption : lsOptions) {
			// 暂时仅控制最大提供5个答案选项,手机端屏幕有限
			if(mapId2QuestionVO.get(questionOption.getQuestionId()).getOptionList().size() < 5) {
				mapId2QuestionVO.get(questionOption.getQuestionId()).getOptionList().add(questionOption);
			}
		}
		
		// 修改试题类型
		for (QuestionVO question : lsQuestions) {
			question.setAnswer(""); // 清空正确答案
			/*if(Const.QUESTION_TYPE_ID_SINGLE.equals(question.getQuestionTypeId())) {
				question.setQuestionTypeId("single"); // 单选题
			} else if (Const.QUESTION_TYPE_ID_MULTIPLE.equals(question.getQuestionTypeId())) {
				question.setQuestionTypeId("multiple"); // 多选题
			} else if (Const.QUESTION_TYPE_ID_JUDGE.equals(question.getQuestionTypeId())) {
				question.setQuestionTypeId("judge"); // 判断题
			}*/
		}
		
		result = Result.success(lsQuestions);
		// 缓存起来为后续的用户考试提供试题
		CacheUtils.put("QuestionsInExamId_" + examId, result);
		
		return result;
	}

	/**
	 * 获取指定考试的全部试题，包含正确答案和用户答案，仅用于复习，试题不缓存
	 * @param examId
	 * @param examResult 用户答案
	 * @return Result
	 */
	private Result findQuestionsForReview(HttpServletRequest request, String examId, ExamResult examResult) {
		List<QuestionVO> lsQuestions = examQueryService.findListQuestionByExamId(examId);
		List<QuestionOption> lsOptions = examQueryService.findListQuestionOptionByExamId(examId);
		Map<String, QuestionVO> mapId2QuestionVO = Method.convertListToMap(lsQuestions);
		
		// 将试题选项与试题关联
		for (QuestionOption questionOption : lsOptions) {
			// 暂时仅控制最大提供5个答案选项,手机端屏幕有限
			if(mapId2QuestionVO.get(questionOption.getQuestionId()).getOptionList().size() < 5) {
				mapId2QuestionVO.get(questionOption.getQuestionId()).getOptionList().add(questionOption);
			}
		}
		
		@SuppressWarnings("unchecked")
		Map<String, String> mapResults = (Map<String, String>) JSON.parse(examResult.getResult());
		
		// 修改试题类型
		for (QuestionVO question : lsQuestions) {
			/*if(Const.QUESTION_TYPE_ID_SINGLE.equals(question.getQuestionTypeId())) {
				question.setQuestionTypeId("single"); // 单选题
			} else if (Const.QUESTION_TYPE_ID_MULTIPLE.equals(question.getQuestionTypeId())) {
				question.setQuestionTypeId("multiple"); // 多选题
			} else if (Const.QUESTION_TYPE_ID_JUDGE.equals(question.getQuestionTypeId())) {
				question.setQuestionTypeId("judge"); // 判断题
			}*/
			question.setUserAnswer(mapResults.get(question.getId()));
		}
		
		return Result.success(lsQuestions);
	}
	
	/**
	 * 获取登录用户的最近10条历史考试成绩
	 * @param session
	 * @param response
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@RequestMapping(value = "/topMyExamResult", method=RequestMethod.POST)
	@ResponseBody
	public Result topMyExamResult(HttpSession session,
			HttpServletResponse response, HttpServletRequest request) throws Exception {
		List<Exam> lsExams = examQueryService.findExamResultByUserId(UserUtils.getUser(request).getId());
		if(lsExams.size() > 10) {
			return Result.success(lsExams.subList(0, 9));
		}
		return Result.success(lsExams);
	}
}